package main

import (
	"context"
	"fmt"
	"time"
)

type paramKey struct{} // 定义一个类型防止context冲突且不用写那么多"param"的字符串

func main() {
	c := context.WithValue(context.Background(), paramKey{}, "abc") // 一个带有abc参数的context
	c, cancel := context.WithTimeout(c, 5*time.Second)              // 有两种可能被中断,1:5秒到了被中断;2:告诉你要cancel了就中断了
	defer cancel()
	go mainTask(c)

	var cmd string
	for {
		fmt.Scan(&cmd) // 从键盘输入一个值
		if cmd == "c" {
			cancel()
		}
	}
}

func mainTask(c context.Context) {
	fmt.Printf("main task started with param %q\n", c.Value(paramKey{}))

	go func() {
		c1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		smallTask(c1, "task1", 9*time.Second)
	}()
	smallTask(c, "task2", 8*time.Second)
}

func smallTask(c context.Context, name string, d time.Duration) {
	fmt.Printf("%s started with param %q\n", name, c.Value(paramKey{}))
	select {
	case <-time.After(d):
		fmt.Printf("%s done\n", name)
	case <-c.Done(): // 如果从c.Done()这个channel中收到值表示任务中断,可能是cancel了也可能是时间到了。
		fmt.Printf("%s cancelled\n", name)
	}
}
